Skip to content

refactor(storage): caller owns version arithmetic for optimistic locking#149

Merged
sbalabanov merged 1 commit into
mainfrom
fix-optimistic-locking
May 5, 2026
Merged

refactor(storage): caller owns version arithmetic for optimistic locking#149
sbalabanov merged 1 commit into
mainfrom
fix-optimistic-locking

Conversation

@behinddwalls
Copy link
Copy Markdown
Collaborator

@behinddwalls behinddwalls commented May 4, 2026

Summary

Storage Update* methods previously did SET version = version + 1
internally, mutating a value the caller didn't supply and making it
easy for in-memory entity versions to drift from the database. Per
discussion in #C09N26TQLLA, version arithmetic now lives in the
controller: Update* takes both oldVersion (the where-clause guard)
and newVersion (the value to write); the store performs a pure
conditional write.

Controllers compute newVersion = oldVersion + 1 before the call and
only assign entity.Version = newVersion after a successful write,
so error paths leave the in-memory version consistent with the DB.

Updates:

  • RequestStore.UpdateState
  • BatchStore.UpdateState, UpdateScoreAndState
  • BatchDependentStore.UpdateDependents
  • conclude, score, batch controllers + tests
  • Integration storage suite
  • New extension/storage/README.md documenting the contract
  • CLAUDE.md "Optimistic locking" bullet rewritten with the contract
    and a correct example (the prior WithStatus example showed the
    anti-pattern that prompted this change)

Storage Update* methods previously did `SET version = version + 1`
internally, mutating a value the caller didn't supply and making it
easy for in-memory entity versions to drift from the database. Per
discussion in #C09N26TQLLA, version arithmetic now lives in the
controller: Update* takes both oldVersion (the where-clause guard)
and newVersion (the value to write); the store performs a pure
conditional write.

Controllers compute newVersion = oldVersion + 1 before the call and
only assign entity.Version = newVersion after a successful write,
so error paths leave the in-memory version consistent with the DB.

Updates:
- RequestStore.UpdateState
- BatchStore.UpdateState, UpdateScoreAndState
- BatchDependentStore.UpdateDependents
- conclude, score, batch controllers + tests
- Integration storage suite
- New extension/storage/README.md documenting the contract
- CLAUDE.md "Optimistic locking" bullet rewritten with the contract
  and a correct example (the prior WithStatus example showed the
  anti-pattern that prompted this change)
@behinddwalls behinddwalls marked this pull request as ready for review May 4, 2026 18:35
@behinddwalls behinddwalls requested review from a team and sbalabanov as code owners May 4, 2026 18:35
@sbalabanov sbalabanov added this pull request to the merge queue May 5, 2026
Merged via the queue into main with commit 70a4033 May 5, 2026
13 checks passed
@github-actions github-actions Bot deleted the fix-optimistic-locking branch May 5, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants